import collections
import os
import traceback

import numpy as np
import pandas
import pandas as pd
from loguru import logger

from models.global_config import glm
from models.stock_model import StockNumber, DayInfo
from mylib import gen_excel
from mylib.myfile import insert_line


def get_all_stock(need_detail, gen_excel_flag, idx, trade_date, N, stocks, indus_num, indus, log_dir):
    df = pd.read_csv('all.csv')
    all_cnt = 0
    all_down_cnt = 0
    all_down_stock_dict = collections.defaultdict(list)
    indus_dict = collections.defaultdict(int)
    indus_all_dict = collections.defaultdict(int)
    indus_stock_dict = collections.defaultdict(list)
    indus_all_stock_dict = collections.defaultdict(list)
    for row in df.index:
        if stocks is not None and df.loc[row]['ts_code'] not in stocks:
            continue
        sn = StockNumber(df.loc[row])
        sn.list_date = df.loc[row]['list_date']
        if '退' in sn.name:
            continue
        if 'ST' in sn.name:
            continue
        if not str(sn.ts_code).startswith('60') \
                and not str(sn.ts_code).startswith('00'):
            continue
        all_cnt += 1
        indus_all_dict[indus] += 1
        indus_all_stock_dict[indus].append(sn.name)
        if analysis_stock(gen_excel_flag, trade_date, N, sn, log_dir, idx):
            all_down_stock_dict[indus].append(sn.name)
            all_down_cnt += 1
            indus_stock_dict[indus].append(sn.name)
            indus_dict[indus] += 1
            logger.info(f'{trade_date} cnt = {indus_dict[indus]}')

    if 'today' not in log_dir:
        p_path = f'{log_dir}/{indus}_all_{indus_num}.csv'
        if need_detail:
            msg = f'{trade_date},{all_down_cnt},{all_cnt},{list(all_down_stock_dict.items())}'
        else:
            msg = f'{trade_date},{all_down_cnt},{all_cnt}'
        insert_line(p_path, idx, msg)


def analysis_stock(gen_excel_flag, trade_date, N, sn, log_dir, idx):
    csv_path = f'stocks/{sn.ts_code}.csv'
    df2 = pd.read_csv(csv_path)
    q10 = []
    q11 = []
    all_di = []
    parr = 0
    today_di = None
    cnt = 0
    pct_arr = []
    arr_high = []
    arr_low = []
    date_arr = []
    price_arr = []
    delta_days = []
    delta_d = 0
    price_arr_high = []
    price_arr_low = []
    for row2 in df2.index:
        delta_d += 1
        di = DayInfo(sn, df2.loc[row2])
        if int(di.trade_date) > int(trade_date):
            continue
        price_arr_high.append(di.high)
        price_arr_low.append(di.low)
        if cnt > 40:
            break
        if len(q10) == N * 2 + 1:
            ad = all_di[N]
            if max(q10) == q10[N]:
                delta_days.append(-delta_d) if delta_days else delta_days.append(-(delta_d - 6))
                delta_d = 0
                pct = round((parr - q10[N]) / q10[N] * 100, 2)
                pct_arr.append(pct)
                if pct > 0:
                    arr_high.append(round(pct, 2))
                else:
                    arr_low.append(round(pct, 2))
                price_arr.append(q10[N])
                date_arr.append(ad.trade_date)
                parr = q10[N]
                cnt += 1
            elif min(q11) == q11[N]:
                pct = round((parr - q11[N]) / q11[N] * 100, 2)
                pct_arr.append(pct)
                if pct > 0:
                    delta_days.append(delta_d) if delta_days else delta_days.append(delta_d - 6)
                    arr_high.append(round(pct, 2))
                else:
                    delta_days.append(-delta_d) if delta_days else delta_days.append(-(delta_d - 6))
                    arr_low.append(round(pct, 2))
                delta_d = 0
                price_arr.append(q11[N])
                date_arr.append(ad.trade_date)
                parr = q11[N]
                cnt += 1
            all_di.pop(0)
            q10.pop(0)
            q11.pop(0)
        all_di.append(di)
        q10.append(di.high)
        q11.append(di.low)
        if today_di is None:
            parr = di.low
            today_di = di
            price_arr.append(di.low)
            date_arr.append(di.trade_date)
    if not pct_arr:
        return False
    # cal
    median_high = round(np.median(arr_high), 2)
    median_low = round(np.median(arr_low), 2)
    link_code_arr = sn.ts_code.split('.')
    link_code = f'{link_code_arr[1]}{link_code_arr[0]}'
    hyperlink = f'"https://xueqiu.com/S/{link_code}"'
    date_arr_hyp = [f'= HYPERLINK({hyperlink},{d})' for d in date_arr[:-1]]
    data_dict = {
        'date': date_arr_hyp,
        'price': price_arr[:-1],
        'delta_days': delta_days,
        'all_pct': pct_arr,
        'median_high': [median_high] * len(pct_arr),
        'median_low': [median_low] * len(pct_arr),
    }
    if pct_arr[0] > 0:
        max_p = max(price_arr_high[0:abs(delta_days[0])])
        pre_price = round(max_p * (100 + median_low) / 100, 2)
        desc = f' {max_p} ↓ -{median_low}% → {pre_price}'
    else:
        min_p = min(price_arr_low[0:abs(delta_days[0])])
        pre_price = round(min_p * (100 + median_high) / 100, 2)
        desc = f' {min_p} ↑ {median_high}% → {pre_price}'
    title_arr_x = [
        f'arr_low({len(arr_low)}) = {np.sort(arr_low)}',
        f'arr_hight({len(arr_high)}) = {np.sort(arr_high)}',
    ]
    chart_x_title = '\n'.join(title_arr_x)
    title_arr_y = [
        f'median_hight = {median_high}%',
        f'median_low = {median_low}%'
    ]
    chart_y_title = '\n'.join(title_arr_y)
    return_flag = False
    if pct_arr[0] < median_low:
        return_flag = True
    if gen_excel_flag:
        file_path = f'{log_dir}/{sn.industry}_{sn.name}_{sn.ts_code}.xlsx'
        if idx:
            pass
            # df = pandas.read_excel(file_path)
            # sort_pct_arr = sorted(pct_arr)
            # # 计算超跌反弹，当前阶段下跌幅度排前三且今日下跌小于昨日，有反弹迹象
            # if pct_arr[0] < df['all_pct'][0] and pct_arr[0] in sort_pct_arr[:3]:
            #     over_down_file = f'{log_dir}/a_result.csv'
            #     hlink = f'= HYPERLINK({hyperlink},{sn.name})'
            #     with open(over_down_file, 'a+') as fw:
            #         fw.write(
            #             f'{today_di.trade_date},{sn.industry},{hlink},{sn.ts_code},{pct_arr[0]},{median_low},{median_high}\n')
            # else:
            #     os.remove(file_path)
        else:
            gen_excel.export_with_chart(p_data=data_dict,
                                        p_title=f'{sn.ts_code}_{sn.name} {desc}',
                                        p_x_title=chart_x_title,
                                        p_y_title=chart_y_title,
                                        p_file_path=file_path)
    return return_flag


def run(need_detail, gen_excel_flag, log_dir, start_date, end_date, stocks=None, indus_num=None, indus=None, bkd=0, N=6):
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)
    logger.info(f'{log_dir} start')
    for idx, trade_date in enumerate(glm.get_all_trade_days(stocks[0])):
        if trade_date >= start_date:
            continue
        if end_date is not None and trade_date <= end_date:
            break
        if idx > bkd:
            break
        logger.info(f'cal {trade_date}')
        try:
            get_all_stock(need_detail, gen_excel_flag, idx, trade_date, N, stocks, indus_num, indus, log_dir)
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(e)
    logger.info('生成excel运行完成')
